package com.legendframework.dao.yaml;

import com.legendframework.dao.AbstractDao;
import com.legendframework.dao.annotation.Entity;
import com.legendframework.dao.exception.DaoException;
import com.legendframework.dao.support.ClassUtils;
import com.legendframework.dao.utils.DaoStringUtils;
import com.legendframework.dao.wrapper.Wrapper;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public abstract class AbstractYamlDao<T> extends AbstractDao<T> implements Cache<T>{

    /**
     * 数据缓存池
     * 实现存取同步
     */
    private Map<Serializable,T> cache;

    public AbstractYamlDao(Class<T> entityType) {
        super(entityType);
        cache = new HashMap<>();
    }

    /**
     * 修改实体类
     *
     * 如果字段不为空则替换，为空则不替换
     *
     * @param source 需要替换的实体类
     * @param target 目标实体类
     * @return
     */
    protected void updateEntity(T source, T target){
        Class<?> cls = source.getClass();
        List<Field> fields = ClassUtils.getByClass(cls);
        for (Field field : fields) {
            try {
                Object fieldResult = ClassUtils.getGetterMethodByField(cls, field).invoke(source);
                if (fieldResult == null) {
                    continue;
                }
                //把该字段的值替换到目标实体类中
                ClassUtils.getSetterMethodByField(cls,field).invoke(target,fieldResult);
            } catch (Throwable e) {
                throw new DaoException("获取实体类字段数据时失败",e);
            }
        }
    }
    /**
     * 获取实体类上的YamlFile注解信息
     * @param path 绝对路径前缀
     * @param typeClass 实体类
     * @return
     */
    protected String getYamlFileName(String path , Class<T> typeClass){
        String fileName = null;
        if (typeClass.isAnnotationPresent(Entity.class)) {
            Entity annotation = typeClass.getAnnotation(Entity.class);
            if (DaoStringUtils.isNotEmpty(annotation.yamlFileName())) {
                fileName = annotation.yamlFileName();
            }
        }
        if (fileName == null) {
            throw new DaoException("实体类必须实现@Entity注解中的yamlFileName字段");
        }
        if (path.endsWith("/")) {
            if (fileName.startsWith("/")) {
                return path+fileName.substring(1);
            }else {
                return path+fileName;
            }
        }else if (fileName.startsWith("/")){
            return path+fileName;
        }else {
            return path+"/"+fileName;
        }
    }


    /**
     * 获取所有数据
     * @return
     */
    abstract List<T> getAll();

    /**
     * 对条件构造器的解析
     *
     * @param wrapper 条件
     * @return
     */
    protected List<T> filter(Wrapper<T> wrapper){
        if (wrapper == null) {
            return getAll();
        }
        return getAll().stream().filter(wrapper::check).collect(Collectors.toList());
    }

    /**
     * 获取所有缓存数据
     * @return
     */
    @Override
    public Collection<T> getCacheAll() {
        return cache.values();
    }

    /**
     * 获取一条缓存数据
     * @param key key
     * @return
     */
    @Override
    public T getCacheOne(Serializable key) {
        return cache.get(key);
    }

    /**
     * 根据Key删除一条数据
     * @param key key
     */
    @Override
    public void deleteCacheByKey(Serializable key) {
        cache.remove(key);
    }

    /**
     * 删除多个Key的数据
     * @param keys keyes
     */
    @Override
    public void deleteCacheBatchKey(Serializable[] keys) {
        if (keys == null) {
            return;
        }
        for (Serializable key : keys) {
            deleteCacheByKey(key);
        }
    }

    /**
     * 放置一条数据
     * @param key key
     * @param t 数据
     */
    @Override
    public void putCacheOne(Serializable key, T t) {
        cache.put(key,t);
    }

    /**
     * put多个数据
     * @param map map
     */
    @Override
    public void putCacheBatch(Map<Serializable, T> map) {
        cache.putAll(map);
    }
}
